{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Histograms of Color\n",
    "\n",
    "Let's go back to our classification task: classifying images as day or night. You've looked at using raw pixel values to construct a brightness feature and now we'll look at histograms of pixel intensity (color histograms) as **feature vectors**.\n",
    "\n",
    "Features can be arrays of useful values. Even the filtered images you've been creating are considered feature extracted images. Feature vectors are 1D arrays (or lists) of values, and they can be used when a single value is just not enough to classify an image.\n",
    "\n",
    "In this notebook you'll see how to create a common type of feature vector: a **histogram**. A histogram is a graphical display of data that shows bars of different heights. Each bar groups data (in this case, pixel values) into ranges and the height of each bar indicates the number of times the data falls into that range. So, a taller bar show that more data falls in that specific range.\n",
    "\n",
    "Let's see what an HSV color histogram looks like."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Import resources"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 # computer vision library\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimg\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Read in and standardize day and night images\n",
    "\n",
    "We'll be analyzing two images: one day and one night from our training set of data; of the same scene. These have yet to be standardized, so they are resized to be the same."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Read in a day and a night image\n",
    "# These are directly extracted by name -- do not change\n",
    "day_image = mpimg.imread(\"day_night_images/training/day/20151102_074952.jpg\")\n",
    "night_image = mpimg.imread(\"day_night_images/training/night/20151102_175445.jpg\")\n",
    "\n",
    "\n",
    "# Make these images the same size\n",
    "width = 1100\n",
    "height = 600\n",
    "night_image = cv2.resize(night_image, (width, height))\n",
    "day_image = cv2.resize(day_image, (width, height))\n",
    "\n",
    "# Visualize both images\n",
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))\n",
    "ax1.set_title('night')\n",
    "ax1.imshow(night_image)\n",
    "ax2.set_title('day')\n",
    "ax2.imshow(day_image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create HSV histograms\n",
    "\n",
    "First, convert these images to HSV colorspace. Then use numpy's [histogram function](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.histogram.html) to bin the color values into ranges. Bins are ranges of values like 0-15 for dark intensities or 200-255 for bright values.\n",
    "\n",
    "With np.histogram(), you don't have to specify the number of bins or the range, but here I've arbitrarily chosen 32 bins and specified range=(0, 256) in order to get orderly bin sizes. np.histogram() returns a tuple of two arrays. In this case, for example, h_hist[0] contains the counts in each of the bins and h_hist[1] contains the bin edges (so it is one element longer than h_hist[0]).\n",
    "\n",
    "To plot these results, we can compute the bin centers from the bin edges. Each of the histograms in this case have the same bins, so I'll just use the rhist bin edges: you can define the number of bins."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def hsv_histograms(rgb_image):\n",
    "    # Convert to HSV\n",
    "    hsv = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV)\n",
    "\n",
    "    # Create color channel histograms\n",
    "    h_hist = np.histogram(hsv[:,:,0], bins=32, range=(0, 180))\n",
    "    s_hist = np.histogram(hsv[:,:,1], bins=32, range=(0, 256))\n",
    "    v_hist = np.histogram(hsv[:,:,2], bins=32, range=(0, 256))\n",
    "    \n",
    "    # Generating bin centers\n",
    "    bin_edges = h_hist[1]\n",
    "    bin_centers = (bin_edges[1:]  + bin_edges[0:len(bin_edges)-1])/2\n",
    "\n",
    "    # Plot a figure with all three histograms\n",
    "    fig = plt.figure(figsize=(12,3))\n",
    "    plt.subplot(131)\n",
    "    plt.bar(bin_centers, h_hist[0])\n",
    "    plt.xlim(0, 180)\n",
    "    plt.title('H Histogram')\n",
    "    plt.subplot(132)\n",
    "    plt.bar(bin_centers, s_hist[0])\n",
    "    plt.xlim(0, 256)\n",
    "    plt.title('S Histogram')\n",
    "    plt.subplot(133)\n",
    "    plt.bar(bin_centers, v_hist[0])\n",
    "    plt.xlim(0, 256)\n",
    "    plt.title('V Histogram')\n",
    "    \n",
    "    return h_hist, s_hist, v_hist\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Call the function for \"night\"\n",
    "night_h_hist, night_s_hist, night_v_hist = hsv_histograms(night_image)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Call the function for \"day\"\n",
    "day_h_hist, day_s_hist, day_v_hist = hsv_histograms(day_image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Look at the differences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Which bin do most V values fall in?\n",
    "# Does the Hue channel look helpful?\n",
    "# What patterns can you see that might distinguish these two images?\n",
    "\n",
    "# Out of 32 bins, if the most common bin is in the middle or high up, then it's likely day\n",
    "fullest_vbin_day = np.argmax(day_v_hist[0])\n",
    "fullest_vbin_night = np.argmax(night_v_hist[0])\n",
    "\n",
    "\n",
    "print('Fullest Value bin for day: ', fullest_vbin_day)\n",
    "print('Fullest Value bin for night: ', fullest_vbin_night)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## TODO: Create and look at RGB histograms\n",
    "# Practice what you've learned and look at RGB color histograms of these same images"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Summations to create Feature Vectors\n",
    "\n",
    "To keep spatial information, it is also a useful technique to sum up pixel values along the columns or rows of an image. This allows you to see spikes in varirous color values over space.\n",
    "\n",
    "Let's look at the night image as an example; it's mostly dark but has a lot of little bright spots from artificial lights. I'll look at the Value component  in the image, sum up those pixel values along the columns using np.sum(), and I'll plot that summation.\n",
    "\n",
    "### TODO: Sum the V component of the day image and compare the two"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert the night image to HSV colorspace\n",
    "hsv_night = cv2.cvtColor(night_image, cv2.COLOR_RGB2HSV)\n",
    "\n",
    "# Isolate the V component\n",
    "v = hsv_night[:,:,2]\n",
    "\n",
    "# Sum the V component over all columns (axis = 0)\n",
    "v_sum = np.sum(v[:,:], axis=0)\n",
    "\n",
    "\n",
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))\n",
    "\n",
    "ax2.set_title('Value sum over columns')\n",
    "ax1.plot(v_sum)\n",
    "\n",
    "ax2.set_title('Original image')\n",
    "ax2.imshow(night_image, cmap='gray')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
